﻿/*
** Xin YUAN, 2023, BSD (2)
*/

////////////////////////////////////////////////////////////////////////////////
#ifndef __X_SYS_SYNC_H__
#define __X_SYS_SYNC_H__
////////////////////////////////////////////////////////////////////////////////

//sync_mutex

class sync_mutex
{
public:
	sync_mutex() noexcept : m_bInitialized(false)
	{
	}
	sync_mutex(const sync_mutex&) = delete;
	~sync_mutex() noexcept
	{
		Term();
	}

	sync_mutex& operator=(const sync_mutex&) = delete;

	bool IsValid() const noexcept
	{
		return m_bInitialized;
	}

	bool Init() noexcept
	{
		assert( !IsValid() );
		if ( ::pthread_mutex_init(&m_mutex, NULL) != 0 )  //error number
			return false;
		m_bInitialized = true;
		return true;
	}
	void Term() noexcept
	{
		if ( m_bInitialized ) {
			int ret = ::pthread_mutex_destroy(&m_mutex);
			(void)ret;
			assert( ret == 0 );  //or error number
			m_bInitialized = false;
		}
	}

	void Lock() noexcept
	{
		assert( m_bInitialized );
		int ret = ::pthread_mutex_lock(&m_mutex);
		(void)ret;
		assert( ret == 0 );  //or error number
	}
	void Unlock() noexcept
	{
		assert( m_bInitialized );
		int ret = ::pthread_mutex_unlock(&m_mutex);
		(void)ret;
		assert( ret == 0 );  //or error number
	}

private:
	pthread_mutex_t m_mutex;
	bool m_bInitialized;

private:
	friend class sync_condition;
};

//sync_condition

class sync_condition
{
public:
	sync_condition() noexcept : m_bInitialized(false)
	{
	}
	sync_condition(const sync_condition&) = delete;
	~sync_condition() noexcept
	{
		Term();
	}

	sync_condition& operator=(const sync_condition&) = delete;

	void Init() noexcept
	{
		assert( !m_bInitialized );
		int res = ::pthread_cond_init(&m_cv, NULL);
		(void)res;
		assert( res == 0 );  //or error number
		m_bInitialized = true;
	}

	void Wait(sync_mutex& mtx) noexcept
	{
		assert( m_bInitialized );
		int ret = ::pthread_cond_wait(&m_cv, &mtx.m_mutex);
		(void)ret;
		assert( ret == 0 );  //or error number
	}
	void Signal() noexcept
	{
		assert( m_bInitialized );
		int ret = ::pthread_cond_signal(&m_cv);
		(void)ret;
		assert( ret == 0 );  //or error number
	}

private:
	void Term() noexcept
	{
		if( m_bInitialized ) {
			int res = ::pthread_cond_destroy(&m_cv);
			(void)res;
			assert( res == 0 );  //or error number
			m_bInitialized = false;
		}
	}

private:
	pthread_cond_t m_cv;
	bool m_bInitialized;
};

////////////////////////////////////////////////////////////////////////////////
#endif
////////////////////////////////////////////////////////////////////////////////
